/**
 * Copyright 2018 orivil.com. All rights reserved.
 * Use of this source code is governed by a MIT-style
 * license that can be found at https://mit-license.org.
 */

package mux

import (
	"net/http"
	"os"
	"context"
	"net/http/pprof"
	"gitee.com/tugoer/orivil/log"
	"time"
	"gitee.com/tugoer/orivil/grace"
)

// graceful shutdown server
var Server = &http.Server{Handler: Handler, ErrorLog: log.Emergency, WriteTimeout: 20 * time.Second, ReadTimeout: 20 * time.Second}

var closeFunc []func()

/** TODO: 程序第一次启动时保存 socket file。
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified unix socket (ie. a file).
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) RunUnix(file string) (err error) {
	debugPrint("Listening and serving HTTP on unix:/%s", file)
	defer func() { debugPrintError(err) }()

	os.Remove(file)
	listener, err := net.Listen("unix", file)
	if err != nil {
		return
	}
	defer listener.Close()
	err = http.Serve(listener, engine)
	return
}
 */

// 开始监听端口
func Run() {
	addDefaultHandler()
	// 监听关闭信号
	closed := grace.ListenSignal(func() error {
		return Server.Shutdown(context.Background())
	})
	var err error
	if Env.Listen.SSL {
		// start redirect server(http -> https)
		go func() {
			var handler http.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) {
				http.Redirect(writer, request, "https://" + Env.Listen.ServerName + request.RequestURI, http.StatusMovedPermanently)
			}
			err := http.ListenAndServe(Env.Listen.HttpPort, handler)
			log.Emergency.Printf("rewrite server closed: %s\n", err)
		}()
		// start https server
		log.Init.Printf("pid:[%d] listen on: [%s]\n", os.Getpid(), Env.Listen.HttpsPort)
		Server.Addr = Env.Listen.HttpsPort
		err = Server.ListenAndServeTLS(Env.Listen.SSLCertificate, Env.Listen.SSLCertificateKey)
	} else {
		// start http server
		log.Init.Printf("pid:[%d] listen on: http://localhost%s\n", os.Getpid(), Env.Listen.HttpPort)
		Server.Addr = Env.Listen.HttpPort
		err = Server.ListenAndServe()
	}
	// handle server error
	if err != http.ErrServerClosed {
		log.Emergency.Fatalf("Server: %s\n", err)
	}
	// 先注册将被后执行
	for ln := len(closeFunc); ln > 0; ln-- {
		closeFunc[ln-1]()
	}
	// wait until server shutdown error
	<-closed
}

// OnShutdown 是 http.Server.RegisterOnShutdown() 的别名, 经过注册的函数将在 Server 关闭的时候调用,
// 需要注意的是: 当 Server 关闭时, 通过该方法注册的函数会被同时执行, 没有先后顺序
func OnShutdown(call func()) {
	Server.RegisterOnShutdown(call)
}

// 注册程序退出时的回调函数, 与 OnShutdown() 函数不同的是: 通过该方法注册的回调函数, 先注册将被后执行.
func BeforeClose(call func()) {
	closeFunc = append(closeFunc, call)
}


func addDefaultHandler() {
	if len(Handler.actions) == 0 {
		// 如果当前没有任何路由被注册，添加一个测试路由
		Handler.Handle(http.MethodGet, "/", func(ctx *Context) {
			ctx.View("hello", "orivil")
		})
	}

	// 添加 pprof 路由
	Handler.Handle("GET", "/debug/pprof/", func(ctx *Context) {
		pprof.Index(ctx.Response, ctx.Request)
	})

	Handler.Handle("GET", "/debug/pprof/cmdline", func(ctx *Context) {
		pprof.Cmdline(ctx.Response, ctx.Request)
	})

	Handler.Handle("GET", "/debug/pprof/profile", func(ctx *Context) {
		pprof.Profile(ctx.Response, ctx.Request)
	})

	Handler.Handle("GET", "/debug/pprof/symbol", func(ctx *Context) {
		pprof.Symbol(ctx.Response, ctx.Request)
	})

	Handler.Handle("GET", "/debug/pprof/trace", func(ctx *Context) {
		pprof.Trace(ctx.Response, ctx.Request)
	})
}